/* TUple.h
 *
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


#if !defined(_TUple_)
#define _TUple_


#include	<stdio.h>
#include <boost/operators.hpp> 
#include <src/miscellaneous/OS_basic.h>


		template <typename T>
      struct make;
/*! \brief One dimensiona vector of static size, std compatible, with a full set of operations.
	A simple class optimizing the memory operatiions because it knows its initial size at compile time.
*/
      template <typename T,OS_int i>
	  class TUple :					private      
		boost::addable< TUple<T,i>          // point + point
    ,	boost::subtractable< TUple<T,i>     // point - point
	,	boost::multipliable2 < TUple<T,i>, T
	,   boost::dividable2 < TUple<T,i>, T
      > > > > 
      {
protected:
  typedef TUple<T,i> This;

public :
	typedef typename T value_type; 
    enum { Dim = i };
            OS_STATIC_CHECK(i>=1);
			typedef T* iterator;
            TUple() {};
			TUple(OS_size n) { //for std::compatibility
				OS_DYNAMIC_CHECK(n==Dim,"this is a non resizable type vector");
			}
            TUple(const TUple<T,i> &t) {
                  memcpy(t_,t.t_,i*sizeof(T));
            };
            void assign(const T &t) {
                  for (OS_int i=0;i<Dim;i++)
					  t_[i] = t;
            };
            ~TUple() {};
            inline void operator()() {
				  T temp(0);
				  set(temp);
            }
            inline T& operator[](OS_int i) {
                  OS_DYNAMIC_CHECK(i>=0 && i<Dim, "indice out of range in TUple");
                  return t_[i];
            };
            inline T& operator[](OS_int i) const {
                  OS_DYNAMIC_CHECK(i>=0 && i<Dim, "indice out of range in TUple");
                  return t_[i];
            };
            inline TUple& operator = (const iterator t) {
                  memcpy(t_,t,i*sizeof(T));
				  return *this;
            };
            inline TUple& operator = (const T &t) {
                  memset(t_,t,i*sizeof(T));
				  return *this;
            };
            inline const TUple<T,i>& operator+=(const TUple<T,i> &from) const {
                  for (OS_int i=0;i<Dim;i++)
					  t_[i] += from.t_[i];
				  return *this;
            };
            inline T operator*=(const TUple<T,i> &from) const {
				  T returned_value(1);
                  for (OS_int i=0;i<Dim;i++)
					  returned_value += t_[i]*from.t_[i];
				  return returned_value;
            };
            inline const TUple<T,i>& operator-=(const TUple<T,i> &from) const {
                  for (OS_int i=0;i<Dim;i++)
					  t_[i] -= from.t_[i];
				  return *this;
            };
            inline const TUple<T,i>& operator *=(const T &from) const {
                  for (OS_int i=0;i<Dim;i++)
					  t_[i] *= from;
				  return *this;
            };
            inline const TUple<T,i>& operator /=(const T &from) const {
                  for (OS_int i=0;i<Dim;i++)
					  t_[i] /= from;
				  return *this;
            };
            inline OS_bool operator < (const TUple<T,i> &from) const {
				for (OS_int i=0;i<Dim;i++) {
					  if (t_[i] >= from.t_[i]) return false;
				}
				 return true; // equality
            };
            inline OS_bool operator == (const TUple<T,i> &from) const {
                  for (OS_int i=0;i<Dim;i++)
					  if (t_[i] != from.t_[i]) return false;
				  return true;
            };
			inline size_t size() const
			{return Dim;};
			inline const iterator begin() const
			{return t_;};
			inline const iterator end() const
			{return t_+size();};

  template <class SK>
  struct Static_traits
  {
    typedef typename SK::Point_2 Static_type;

    static Static_type to_static(const This &o, const typename SK::FT &t, const SK &) {
      return Static_type(o.x()(t), o.y()(t));
    }
  };

protected :
            mutable T    t_[i];
            friend make<T>;
      };

      template <typename T = OS_double>
      struct make_3
      {
		  operator TUple<T,3> ()
		  {
			  return _t;
		  };
		  make_3(const T& t1,const T& t2,const T& t3) {
            _t[0] = t1;
            _t[1] = t2;
            _t[2] = t3;
		  };
		 TUple<T,3> _t;
	  };


      template <typename T = OS_double>
      struct make_2
      {
		  operator TUple<T,2> ()
		  {
			  return _t;
		  };
		  make_2(const T& t1,const T& t2) {
            _t[0] = t1;
            _t[1] = t2;
		  };
		 TUple<T,2> _t;
	  };

      template <typename T = OS_double>
      struct make_1
      {
		  operator TUple<T,1> ()
		  {
			  return _t;
		  };
		  make_1(const T& t1) {
            _t[0] = 1;
		  };
		 TUple<T,1> _t;
	  };

      template <typename T, OS_int i>
      std::ostream& operator<< (std::ostream& o, const TUple<T,i> & t)
      {
            o << "( ";
            for (OS_int j = 0; j < TUple<T,i>::Dim; j ++) {
                  o << t[j];
				 if (j!= TUple<T,i>::Dim-1)
					 o << ",";
            };
            o << " )";
            return o;
      };
template <typename T, OS_int i>
std::istream &operator>>(std::istream &in, const TUple<T,i> & t)
{
	char c;
	in >> c;
  if (c != '(') {
    in.setstate(std::ios_base::failbit);
    return in;
  }
   for (OS_int j = 0; j < TUple<T,i>::Dim; j ++) {
          in >> t[j];
		  in >> c;
		  if (c != ',' && j != TUple<T,i>::Dim -1) {
			in.setstate(std::ios_base::failbit);
			return in;
		  }
  }

  if (c != ')') in.setstate(std::ios_base::failbit);
  return in;
}


#endif _TUple_
